package com.sz.app.oss.api.logistics.billing;

import com.sz.app.oss.api.logistics.billing.dto.*;
import com.sz.biz.app.web.BaseController;
import com.sz.biz.common.constants.SystemConstants;
import com.sz.biz.logistics.billing.dto.QuotationCalcObject;
import com.sz.biz.logistics.billing.dto.QuotationCalcResult;
import com.sz.biz.logistics.billing.service.QuotationCalcService;
import com.sz.biz.logistics.constants.ProductGroupCode;
import com.sz.biz.logistics.core.entity.ProductGroup;
import com.sz.biz.logistics.core.entity.ProductServiceRel;
import com.sz.biz.logistics.core.entity.Service;
import com.sz.biz.logistics.core.service.ProductGroupService;
import com.sz.biz.logistics.core.service.ServiceService;
import com.sz.biz.logistics.ord.entity.OrdOrder;
import com.sz.biz.logistics.ord.entity.OrdServiceAssign;
import com.sz.biz.logistics.ord.service.OrdOrderService;
import com.sz.biz.logistics.ord.service.OrdOrderServiceAssignService;
import com.sz.biz.logistics.ord.service.OrdTrackingMessageService;
import com.sz.biz.logistics.ord.service.OrderCalcJobService;
import com.sz.common.base.dto.ResultDto;
import com.sz.common.base.utils.EntityUtils;
import com.sz.common.base.utils.ObjectUtils;
import com.sz.common.base.utils.StringUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

/**
 * Function: 计费的接口. <br>
 * Date: 2017年05月05日 14:35 <br>
 * Author: wentao.chang
 */
@RestController
@RequestMapping("/api/v1/biz/calc")
@Api(description = " ", tags = "038、计费管理")
public class QuotationCalcController extends BaseController {
    @Autowired
    private QuotationCalcService quotationCalcService;
    @Autowired
    private OrdOrderService orderService;

    @Autowired
    private OrderCalcJobService orderCalcJobService;

    @Autowired
    private ProductGroupService productGroupService;

    @Autowired
    private OrdOrderServiceAssignService ordOrderServiceAssignService;

    @Autowired
    private ServiceService serviceService;
    @Autowired
    private OrdTrackingMessageService trackingMessageService;

    @ApiOperation(value = "手动调用计算运单价格的接口", notes = "-")
    @RequestMapping(value = "/cron", method = {RequestMethod.POST})
    public ResultDto calcCostCron() throws ExecutionException, InterruptedException {
        orderCalcJobService.calcCron(1);
        orderCalcJobService.calcCron(2);
        ResultDto result = new ResultDto();
        result.setMsg("计算成功（只计算最近7天的单）");
        result.setData(1);
        return result;
    }

    @ApiOperation(value = "手动调用计算运单价格汇率的接口", notes = "-")
    @RequestMapping(value = "/exchangecron", method = {RequestMethod.POST})
    public ResultDto calcExchangeCron() throws ExecutionException, InterruptedException {
        orderCalcJobService.calcExchangeRateCron();
        ResultDto result = new ResultDto();
        result.setMsg("计算成功");
        result.setData(1);
        return result;
    }

    @ApiOperation(value = "服务成本计费", notes = "-")
    @RequestMapping(value = "/cost/service", method = {RequestMethod.POST})
    public ResultDto save(@RequestBody @ApiParam(value = "计费对象", required = true) ServiceCalcDto dto)
            throws ExecutionException, InterruptedException {

        PackageWeightResult pwr = handleWeightVolume(dto.getPackages());

        QuotationCalcObject calcResults = quotationCalcService.calcServiceCostPrice(
                dto.getServiceUid(), dto.getCalcDate(), dto.getSettleMentId(), dto.getCargoTypeCode(),
                pwr.getWeight(), pwr.getVolume(), pwr.getUnitCode(),
                dto.getFromCountry(), dto.getFromProvince(), dto.getFromCity(),
                dto.getFromArea(), dto.getFromStreet(), dto.getFromPostcode(),
                dto.getToCountry(), dto.getToProvince(), dto.getToCity(),
                dto.getToArea(), dto.getToStreet(), dto.getToPostcode());
        ResultDto result = new ResultDto();
        result.setMsg("计算结果");
        result.setData(calcResults);
        return result;

    }

    @ApiOperation(value = "计算运单的销售价格", notes = "-")
    @RequestMapping(value = "/sale/{waybillNo}", method = {RequestMethod.GET})
    public ResultDto saleWaybill(@PathVariable String waybillNo)
            throws ExecutionException, InterruptedException {
        String orderNo = orderService.findOrderNoByWaybillNo(waybillNo);
        QuotationCalcObject calcResult = quotationCalcService.calcOrderSalePrice(orderNo, false);
        BigDecimal totalAmount = BigDecimal.ZERO;
        BigDecimal totalCustCurrencyAmount = BigDecimal.ZERO;
        for (QuotationCalcResult result : calcResult.getResult()) {
            if (result.isHasResult()) {
                BigDecimal ca = result.getCustCurrencyAmount() == null ? BigDecimal.ZERO : result.getCustCurrencyAmount();
                totalCustCurrencyAmount = totalCustCurrencyAmount.add(ca);
                totalAmount = totalAmount.add(result.getAmount());
            }
        }
        calcResult.setAmount(totalAmount);
        calcResult.setCustCurrencyAmount(totalCustCurrencyAmount);
        ResultDto result = new ResultDto();
        result.setMsg("计算结果");
        result.setData(calcResult);
        return result;

    }

    @ApiOperation(value = "计算运单的成本价格", notes = "-")
    @RequestMapping(value = "/cost/{waybillNo}", method = {RequestMethod.GET})
    public ResultDto costwayBill(@PathVariable String waybillNo)
            throws ExecutionException, InterruptedException {
        String orderNo = orderService.findOrderNoByWaybillNo(waybillNo);
        QuotationCalcObject calcResults = quotationCalcService.calcOrderCostPrice(orderNo);
        BigDecimal total = BigDecimal.ZERO;
        for (QuotationCalcResult result : calcResults.getResult()) {
            if (result.isHasResult()) {
                total = total.add(result.getAmount());
            }
        }
        calcResults.setAmount(total);
        ResultDto result = new ResultDto();
        result.setMsg("计算结果");
        result.setData(calcResults);
        return result;

    }


    @ApiOperation(value = "产品销售计费，试算", notes = "-")
    @RequestMapping(value = "/sale/product", method = {RequestMethod.POST})
    public ResultDto productCalc(@RequestBody @ApiParam(value = "计费对象", required = true) ProductCalcDto dto)
            throws ExecutionException, InterruptedException {
        dto.setDomainId(SystemConstants.SystemType.OPERTION);//1、运营系统 2、客户系统
        PackageWeightResult pwr = handleWeightVolume(dto.getPackages());
        if (!CollectionUtils.isEmpty(dto.getGroupType()) && dto.getGroupType().contains(ProductGroupCode.LAND_TRANSPORT)) {
            dto.getGroupType().add(ProductGroupCode.WAREHOSE_INTEGRATION);
            dto.getGroupType().add(ProductGroupCode.COLD_CHAIN_LOGISTICS);
            dto.getGroupType().add(ProductGroupCode.ENGINEERING_LOGISTICS);
        }
        QuotationCalcObject calcResults = quotationCalcService.calcProductSalePrice(
                dto.getCustomerId(), dto.getGroupType(),
                dto.getProductUid(), dto.getCalcDate(), dto.getCargoTypeCode(), "",
                pwr.getWeight(), pwr.getVolume(), pwr.getUnitCode(), BigDecimal.ZERO,
                dto.getFromCountry(), dto.getFromProvince(), dto.getFromCity(),
                dto.getFromArea(), dto.getFromStreet(), dto.getFromPostcode(),
                dto.getFromCountry(), dto.getFromProvince(), dto.getFromCity(),
                dto.getFromArea(), dto.getFromStreet(), dto.getFromPostcode(),
                dto.getToCountry(), dto.getToProvince(), dto.getToCity(),
                dto.getToArea(), dto.getToStreet(), dto.getToPostcode(),
                dto.getStartPort(), dto.getEndPort(), Collections.singletonList(""),
                true, true,
                dto.getDomainId());

        List<ProductGroup> pgs = productGroupService.list();
        Map<String, ProductGroup> pgMap = EntityUtils.getStringKeyMapFromBeans(pgs, "id");

        calcResults.getResult().forEach(item -> {
            ProductGroup pg = pgMap.get(item.getGroupId() + "");
            if (pg != null) {
                item.setGroupName(pg.getParentId() == 1 ? "海运" : (pg.getParentId() == 6 ? "空运" : "速递"));
            }
        });
        calcResults.getResult().sort((item1, item2) ->
                (item1.getGroupName() + item1.getProductName()).compareTo(item2.getGroupName() + item2.getProductName())
        );
        ResultDto result = new ResultDto();
        result.setMsg("计算结果");
        result.setData(calcResults);
        return result;

    }

    @ApiOperation(value = "订单销售费用预估", notes = "-")
    @RequestMapping(value = "/order/sale", method = {RequestMethod.POST})
    public ResultDto orderCalc(@RequestBody @ApiParam(value = "计费对象", required = true) ProductCalcDto dto)
            throws ExecutionException, InterruptedException {
        dto.setDomainId(1);
        QuotationCalcObject calcResults = quotationCalcService.calcProductSalePrice(
                dto.getCustomerId(), dto.getGroupType(),
                dto.getProductUid(), dto.getCalcDate(), dto.getCargoTypeCode(), "",
                dto.getWeight(), BigDecimal.ZERO, dto.getUnitCode(), dto.getAnnouncePrice(),
                dto.getFromCountry(), dto.getFromProvince(), dto.getFromCity(),
                dto.getFromArea(), dto.getFromStreet(), dto.getFromPostcode(),
                dto.getFetchCountry(), dto.getFetchProvince(), dto.getFetchCity(),
                dto.getFetchArea(), dto.getFetchStreet(), dto.getFetchPostcode(),
                dto.getToCountry(), dto.getToProvince(), dto.getToCity(),
                dto.getToArea(), dto.getToStreet(), dto.getToPostcode(), dto.getStartPort(), dto.getEndPort(),
                dto.getOptionServiceTypes(), false, false,
                dto.getDomainId());

        final BigDecimal[] amount = {BigDecimal.ZERO};
        final String[] currency = {""};
        calcResults.getResult().forEach(item -> {
            currency[0] = item.getCurrencyCode();
            if (item.isHasResult()) {
                if (!item.isOptional()) {
                    amount[0] = amount[0].add(item.getAmount());
                }
                if (item.isOptional() && dto.getOptionServiceTypes().contains(item.getServiceTypCode())) {
                    amount[0] = amount[0].add(item.getAmount());
                }
            }
        });
        Map<String, Object> map = new HashMap<>(16);
        map.put("currency", currency[0]);
        map.put("amount", amount[0]);
        ResultDto result = new ResultDto();
        result.setMsg("计算结果");
        result.setData(map);
        return result;

    }

    private PackageWeightResult handleWeightVolume(List<PackageWeightDto> packages) {
        PackageWeightResult pwr = new PackageWeightResult();
        String weightUnit = "kg";
        BigDecimal weight = BigDecimal.ZERO;
        BigDecimal volume = BigDecimal.ZERO;
        for (PackageWeightDto weightDto : packages) {
            weightUnit = weightDto.getUnitCode();
            if (weightDto.getWeight() != null) {
                weight = weight.add(weightDto.getWeight());
            }
            if (weightDto.getWidth() != null && weightDto.getHeight() != null && weightDto.getLength() != null) {
                BigDecimal singleVolume = weightDto.getWidth().multiply(weightDto.getHeight()).multiply(weightDto.getLength());
                volume = volume.add(singleVolume);
            }
        }
        pwr.setWeight(weight);
        pwr.setVolume(volume);
        pwr.setUnitCode(weightUnit);
        return pwr;
    }

    @ApiOperation(value = "查看订单的流转", notes = "-")
    @RequestMapping(value = "/orders/{waybillNo}/process", method = {RequestMethod.GET})
    public ResultDto ordersProcess(@PathVariable String waybillNo) {
        OrdOrder ordOrder = orderService.findByWaybillNo(waybillNo);
        String serviceTypeCode="";
        ProductServiceRel productServiceRel = trackingMessageService
                .findCurServiceByTracking(ordOrder.getWaybillNo(), ordOrder.getProductUid(), ordOrder.getCreateTime());
        if(!ObjectUtils.isEmpty(productServiceRel)){
            serviceTypeCode = productServiceRel.getServiceTypeCode();
        }
        OrdServiceAssign osa = ordOrderServiceAssignService.findByOrderNosWithoutAssign(ordOrder.getOrderNo());
        if (osa == null) {
            ordOrderServiceAssignService.calc(ordOrder.getOrderNo(),serviceTypeCode);
            osa = ordOrderServiceAssignService.findByOrderNosWithoutAssign(ordOrder.getOrderNo());
        }
        OrdServiceAssignDto dto = new OrdServiceAssignDto();
        BeanUtils.copyProperties(osa, dto);
        if (!StringUtils.isEmpty(dto.getSt001Uid())) {
            Service service = serviceService.findById(dto.getSt001Id());
            if (service != null) {
                dto.setSt001Name(service.getName());
            }
        }
        if (!StringUtils.isEmpty(dto.getSt002Uid())) {
            Service service = serviceService.findById(dto.getSt002Id());
            if (service != null) {
                dto.setSt002Name(service.getName());
            }
        }
        if (!StringUtils.isEmpty(dto.getSt003Uid())) {
            Service service = serviceService.findById(dto.getSt003Id());
            if (service != null) {
                dto.setSt003Name(service.getName());
            }
        }
        if (!StringUtils.isEmpty(dto.getSt004Uid())) {
            Service service = serviceService.findById(dto.getSt004Id());
            if (service != null) {
                dto.setSt004Name(service.getName());
            }
        }
        if (!StringUtils.isEmpty(dto.getSt005Uid())) {
            Service service = serviceService.findById(dto.getSt005Id());
            if (service != null) {
                dto.setSt005Name(service.getName());
            }
        }
        if (!StringUtils.isEmpty(dto.getSt006Uid())) {
            Service service = serviceService.findById(dto.getSt006Id());
            if (service != null) {
                dto.setSt006Name(service.getName());
            }
        }
        dto.setMsgs(osa.getCalcMsg());
        ResultDto result = new ResultDto();
        result.setMsg(dto.getIsAssignOk() ? "路径计算成功" : "路径计算失败");
        result.setData(dto);
        return result;
    }

}
